package org.halk.controller;

import cn.hutool.core.date.DateUtil;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamResolution;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.halk.util.CameraUtil;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;

/**
 * 获取最新图片或者视频流
 *
 * @Author halk
 * @Date 2024/6/6 下午2:51
 **/
@Controller
@RequiredArgsConstructor
@Slf4j
public class ImageController {

    private final CameraUtil cameraUtil;
    private final SimpMessagingTemplate messagingTemplate;

    @GetMapping("/last")
    public String getLast(Model model, HttpServletRequest request) {
        String clientIp = getClientIp(request);
        log.info("图片查看访问 - IP: {}, User-Agent: {}", clientIp, request.getHeader("User-Agent"));

        model.addAttribute("last", DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd HH:mm:ss"));
        return "lastImage.html";
    }

    @GetMapping("/last/image")
    public ResponseEntity<FileSystemResource> getLastImage() {
        File file = cameraUtil.getRealTimeImage();

        if (file.exists() && file.isFile()) {
            HttpHeaders headers = new HttpHeaders();
            // 或者 MediaType.IMAGE_PNG，根据图片格式
            headers.setContentType(MediaType.IMAGE_JPEG);
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(file.length())
                    .body(new FileSystemResource(file));
        } else {
            throw new RuntimeException("Image not found");
        }
    }

    @GetMapping("/video")
    public String videoPage() {
        return "videoStream";
    }

    /**
     * 实时视频流接口 - 使用MJPEG技术
     */
    @GetMapping("/video/stream")
    public void streamVideo(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 获取访问者详细信息
        String clientIp = getClientIp(request);
        String userAgent = request.getHeader("User-Agent");
        String referer = request.getHeader("Referer");
        String language = request.getHeader("Accept-Language");
        String acceptEncoding = request.getHeader("Accept-Encoding");

        // 记录访问开始日志
        log.info("视频流访问开始 - IP: {}, User-Agent: {}, Referer: {}, Language: {}, Encoding: {}",
                clientIp, userAgent, referer, language, acceptEncoding);

        // 设置响应内容类型为MJPEG
        response.setContentType("multipart/x-mixed-replace; boundary=frame");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");

        Webcam webcam = null;
        OutputStream out = null;
        long startTime = System.currentTimeMillis();
        int frameCount = 0;

        try {
            // 获取并打开摄像头
            webcam = Webcam.getDefault();
            if (webcam == null) {
                throw new RuntimeException("No webcam found");
            }

            // 设置摄像头分辨率
            webcam.setViewSize(WebcamResolution.VGA.getSize());
            webcam.open();

            // 获取输出流
            out = response.getOutputStream();

            // 持续推送图像帧
            while (!Thread.currentThread().isInterrupted()) {
                // 获取摄像头图像
                BufferedImage image = webcam.getImage();
                if (image == null) {
                    continue;
                }

                // 将图像转换为字节数组
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(image, "JPEG", baos);
                byte[] imageBytes = baos.toByteArray();
                baos.close();

                // 写入MJPEG帧边界和头信息
                out.write("--frame\r\n".getBytes());
                out.write("Content-Type: image/jpeg\r\n".getBytes());
                out.write("Content-Length: ".getBytes());
                out.write(String.valueOf(imageBytes.length).getBytes());
                out.write("\r\n\r\n".getBytes());

                // 写入图像数据
                out.write(imageBytes);
                out.write("\r\n".getBytes());
                out.flush();

                // 增加帧数计数
                frameCount++;

                // 每60秒记录一次日志（循环输出）
                long currentTime = System.currentTimeMillis();
                if (currentTime - startTime >= 2000) {
                    long duration = (currentTime - startTime) / 1000;
                    double fps = frameCount / (double) duration;
                    log.info("视频流访问中 - IP: {}, 持续时间: {}秒, 总帧数: {}, 帧率: {:.2f}fps",
                            clientIp, duration, frameCount, fps);
                    startTime = currentTime;
                    frameCount = 0;
                }

                // 控制帧率（约20fps）
                Thread.sleep(50);
            }
        } catch (Exception e) {
            // 连接断开异常是正常的，记录访问结束日志
            long duration = (System.currentTimeMillis() - startTime) / 1000;
            log.info("视频流访问结束 - IP: {}, 持续时间: {}秒, 总帧数: {}",
                    clientIp, duration, frameCount);

            // 非连接断开异常才报错
            if (!(e instanceof IOException && ("Broken pipe".equals(e.getMessage()) ||
                    "Connection reset by peer".equals(e.getMessage())))) {
                log.error("视频流错误 - IP: {}, 错误: {}", clientIp, e.getMessage(), e);
            }
        } finally {
            // 确保摄像头和输出流正确关闭
            if (webcam != null && webcam.isOpen()) {
                webcam.close();
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException ignored) {
                }
            }
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        // 先检查代理头
        String ip = request.getHeader("X-Forwarded-For");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            // 多级代理情况下，取第一个IP
            if (ip.contains(",")) {
                ip = ip.split(",")[0].trim();
            }
            return ip;
        }

        ip = request.getHeader("Proxy-Client-IP");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("WL-Proxy-Client-IP");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_CLIENT_IP");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }

        // 如果以上都没有，使用远程地址
        return request.getRemoteAddr();
    }


    @GetMapping("/websocketVideo")
    public String websocketVideoPage() {
        return "websocketVideo";
    }

    @GetMapping("/startStream")
    @ResponseBody
    public String startStream() {
        new Thread(() -> {
            Webcam webcam = Webcam.getDefault();
            try {
                webcam.setViewSize(WebcamResolution.VGA.getSize());
                webcam.open();

                while (true) {
                    BufferedImage image = webcam.getImage();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(image, "JPEG", baos);
                    byte[] imageBytes = baos.toByteArray();
                    String base64Image = Base64.getEncoder().encodeToString(imageBytes);
                    messagingTemplate.convertAndSend("/topic/videoStream", base64Image);
                    Thread.sleep(50); // 20fps
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                webcam.close();
            }
        }).start();
        return "Stream started";
    }

}
